#include <chrono>
#include <thread>
#include "work/doubleBufQueue.h"
#include "work/workglobal.h"

DBufQueue::DBufQueue(){}
DBufQueue::~DBufQueue(){}

/**
 * 绑定处理函数
 */
bool DBufQueue::InitDbufQueue(workFunc workFunc){
    if (!workFunc) return false;
    m_func = workFunc;
    return true;
}

/**
 * 往双缓冲区存放消息结构体的函数(被子线程调用)
 * @param item 待处理的结构体
 */
void DBufQueue::Push(WorkMsg& msg){
    std::unique_lock<std::mutex> lock(m_swapMutex);
    m_writeQueue.push(std::move(msg));// 移动语义减少拷贝
    lock.unlock(); // 提前释放锁
    m_cond.notify_one();// 唤起阻塞的处理主线程
}

/**
 * 处理读队列消息循环（不需要锁）
 */
void DBufQueue::DealReadQueueMsg(){
    while (!m_readQueue.empty()) {
        WorkMsg msg = std::move(m_readQueue.front());
        m_readQueue.pop();
        m_func(std::move(msg)); // 移动语义减少拷贝
    }
}

/**
 * 进入接收双缓冲区消息的工作循环
 * @return 开启成功与否
 */
bool DBufQueue::BeginWorkCycle(){
    if(m_func == nullptr) return false;

    Log_Info(0, "Work进程进入事件循环...");
    // 如果系统需要终止了就跳出循环
    while(g_stopEvent != 1){
        // 1.取出读消息队列中所有待处理的消息结构体进行处理
        DealReadQueueMsg();
        
        // 2.等待新消息或者超时
        {
            std::unique_lock<std::mutex> lock(m_swapMutex);
            if(m_writeQueue.empty()){
                m_cond.wait_for(lock, std::chrono::milliseconds(200), [this]{
                    return !m_writeQueue.empty();// 条件谓词防止虚假唤醒
                });
            }
            // 不管是否为空，都交换队列（确保即使超时也能处理可能的积压消息）
            m_readQueue.swap(m_writeQueue);
        }// 保证锁离开作用域后自动释放
    }

    // 能出来这里说明进程结束了
    DealAllMsg();// 处理剩余消息
    return true;
}

/**
 * 处理读和写队列所有消息循环
 * 由于Stop_zmq后所有子线程已经结束,已退出多线程环境，可以不加锁
 */
void DBufQueue::DealAllMsg(){
    Log_Info(0, "Work进程从事件循环中退出，开始处理剩余消息");
    Stop_zmq();// 等待所有zmq结束接收（主线程会被阻塞）
    DealReadQueueMsg();// 处理读队列

    // 处理写队列
    while (!m_writeQueue.empty()) {
        WorkMsg msg = std::move(m_writeQueue.front());
        m_writeQueue.pop();
        m_func(std::move(msg)); // 移动语义减少拷贝
    }
}

/**
 * 由zmq队列绑定，存入来自业务进程到双缓冲区队列的函数
 * @param data 字符串，堆上的内存
 * @param size 长度（实际上不太需要）
 */
void PutIntoBufFromLogic(const char* data, size_t& size){
    WorkMsg msg;
    msg.data.assign(data, size);// 深拷贝数据到std::string
    msg.sendProc = (g_procType == 1) ? "game" : "master";
    g_dBufQueue.Push(msg);// msg交由容器管理
    delete[] data;// 已做了深拷贝，可以安全释放掉
}

/**
 * 由zmq队列绑定，存入来自网络进程到双缓冲区队列的函数
 * @param data 字符串，堆上的内存
 * @param size 长度（实际上不太需要）
 */
void PutIntoBufFromNet(const char* data, size_t& size){
    WorkMsg msg;
    msg.data.assign(data, size);// 深拷贝数据到std::string
    msg.sendProc = "net";
    g_dBufQueue.Push(msg);// msg交由容器管理
    delete[] data;// 已做了深拷贝，可以安全释放掉
}